
#include "../../../include/common.h"
#include "../../../include/public/public.h"
#include <errno.h>
#include "collect.h"
// #include "msg.h"
#include "modbusrtu.h"

int ModbusHost_RTU_Addr_Init(cfg_pu_t *pu);
int ModbusHost_RTU_Addr_Run(cfg_pu_t *pu);
int ModbusHost_RTU_Addr_Msg(cfg_pu_t *pu, msg_t *msg);

dlmodule_t ModbusHost_RTU_Addr = {
    ModbusHost_RTU_Addr_Init,
    ModbusHost_RTU_Addr_Run,
    ModbusHost_RTU_Addr_Msg};

static cfg_frame_t *cfg_frame_add(cfg_frame_t *header, cfg_frame_t *new_node)
{
    if (new_node == NULL)
    {
        printf("add new node NULL!\n");
        return NULL;
    }

    if (header == NULL)
    {
        header = new_node;
    }
    else
    {
        cfg_frame_t *cur = header;
        while (cur->next)
        {
            cur = cur->next;
        }
        cur->next = new_node;
    }

    return header;
}

int ModbusHost_RTU_Addr_Init(cfg_pu_t *pu)
{
    UTIL_LOG_I(pu, "init");

    int i;
    cfg_su_t *su = pu->su;
    while (su)
    {
        su_param_t *suparam = (su_param_t *)malloc(sizeof(su_param_t));
        suparam->frames = NULL;

        cfg_frame_t *frame = NULL;
        cfg_ch_t *next_ch = NULL;
        cfg_node_t *next_node = NULL;

        if (su->loop <= 1)
        {
            for (i = 0; i < su->valcntsum; i++)
            {
                cfg_ch_t *ch = su->ch + i;
                cfg_node_t *node = ch->node;
                if (node == NULL)
                {
                    continue;
                }
                // printf("=XX==>> node: %d, name==>> %s, addr : 0x%0X\n",node->id, node->data_name, node->reg_add);
                if (frame == NULL)
                {
                    frame = (cfg_frame_t *)malloc(sizeof(cfg_frame_t));
                    frame->addr = node->reg_add;
                    frame->func = node->fun_num;
                    frame->len = 0;
                    frame->next = NULL;
                    frame->start_id = node->id;
                    frame->end_id = node->id;
                }
                frame->len = node->reg_add - frame->addr + 1;

                if (frame->end_id > ch->node->id)
                {
                    suparam->frames = cfg_frame_add(suparam->frames, frame);
                    frame = NULL;
                    continue;
                }
                frame->end_id = node->id;

                if ((i + 1) < su->valcntsum)
                {
                    next_ch = su->ch + i + 1;
                    next_node = next_ch->node;
                }
                else
                    next_ch = NULL;

                if (next_ch == NULL || next_node == NULL ||
                    (next_node->reg_add - frame->addr > 80)) // FIXME: 分帧最大间隔
                {
                    suparam->frames = cfg_frame_add(suparam->frames, frame);
                    frame = NULL;
                }
            }
        }
        else
        {
            // subdev
            cfg_subdev_t *subdev = su->subdev_list;
            while (subdev)
            {
                for (i = 0; i < subdev->valcntsum; i++)
                {
                    cfg_ch_t *ch = su->ch + i;
                    cfg_node_t *node = ch->node;
                    if (node == NULL)
                    {
                        continue;
                    }
                    // printf("=XX==>> node: %d, name==>> %s, addr : 0x%0X\n",node->id, node->data_name, node->reg_add);
                    if (frame == NULL)
                    {
                        frame = (cfg_frame_t *)malloc(sizeof(cfg_frame_t));
                        frame->addr = node->reg_add;
                        frame->func = node->fun_num;
                        frame->len = 0;
                        frame->next = NULL;
                        frame->start_id = node->id;
                        frame->end_id = node->id;
                    }
                    frame->len = node->reg_add - frame->addr + 1;

                    if (frame->end_id > ch->node->id)
                    {
                        suparam->frames = cfg_frame_add(suparam->frames, frame);
                        frame = NULL;
                        continue;
                    }
                    frame->end_id = node->id;

                    if ((i + 1) < subdev->valcntsum)
                    {
                        next_ch = subdev->ch + i + 1;
                        next_node = next_ch->node;
                    }
                    else
                        next_ch = NULL;

                    if (next_ch == NULL || next_node == NULL ||
                        (next_node->reg_add - frame->addr > 80)) // FIXME: 分帧最大间隔
                    {
                        suparam->frames = cfg_frame_add(suparam->frames, frame);
                        frame = NULL;
                    }
                }

                subdev = subdev->next;
            }
        }

        su->param = (void *)suparam;
        su = su->next;
    }

    return 0;
}

int ModbusHost_RTU_Addr_Run(cfg_pu_t *pu)
{
    UTIL_LOG_I(pu, "running!");

    cfg_serial_t *serial = (cfg_serial_t *)pu->port.setting;
    // 获取串口号
    api_t *api = (api_t *)pu->hanlder.api;
    cfg_basic_t *sys = g_cfg->g_basic;

    char dev[20] = "";
    int err = util_hw_get_serial_dev("AF-HK100", pu->port.type, dev);
    // int err = util_hw_get_serial_dev(g_cfg->g_basic->product, pu->port.type, dev);
    if (err < 0)
    {
        UTIL_LOG_E(pu, "%s get serial device:%s error!", pu->name, pu->port.type);
        return -1;
    }

    printf("-------------------format >>>%s\n", serial->format);

    modbus_t *ctx = modbus_new_rtu(dev, atoi(serial->baudrate),
                                   serial->format[0],
                                   serial->format[1] - '0',
                                   serial->format[2] - '0');

    if (ctx == NULL)
    {
        UTIL_LOG_E(pu, "open serial:%s error!", dev);
        return -1;
    }

    pu_param_t *pu_param = (pu_param_t *)malloc(sizeof(pu_param_t));
    pu_param->ctx = ctx;
    pu_param->cnt = 0;
    pu->hanlder.param = pu_param;

    // 超时时间设置
    int timeout = 500;
    modbus_set_response_timeout(ctx, timeout / 1000, (timeout % 1000) * 1000);
    // 设置调试模式

    modbus_set_debug(ctx, TRUE);

    // 设置自动重连
    modbus_set_error_recovery(ctx, MODBUS_ERROR_RECOVERY_LINK);

    if (modbus_connect(ctx) == -1)
    {
        fprintf(stderr, "Connection failed: %s\n",
                modbus_strerror(errno));
        modbus_free(ctx);
        return -1;
    }
    UTIL_LOG_D(pu, "connect to %s ok", dev);

    cfg_su_t *su = pu->su;
    while (su)
    {
        su_param_t *param = (su_param_t *)su->param;
        cfg_frame_t *frames = param->frames;

        while (frames)
        {
            printf("addr: %d, len -->> %d\n", frames->addr, frames->len);

            frames = frames->next;
        }
        su = su->next;
    }

    while (1)
    {
        collect_frame(ctx, pu);
        sleep(3);
    }
}

int ModbusHost_RTU_Addr_Msg(cfg_pu_t *pu, msg_t *msg)
{
    // api_t* api = (api_t*)pu->hanlder.api;
    // kv_t* kv = (kv_t*)msg->value;

    // switch (msg->type)
    // {
    // case MSG_TYPE_CTRL:
    // {
    //     // 参数设置
    //     while(kv)
    //     {
    //         rb_mem_t* mem = api->get_rb_mem(pu,msg->su,kv->key);
    //         if(mem == NULL)
    //         {
    //             UTIL_LOG_E(pu,"cannot find %s.%s",msg->su,kv->key);
    //             return -1;
    //         }

    //         if(msg_general_ctrl(mem,kv->value) < 0)
    //         {
    //             util_ch_get_string_val(mem->ch,kv->value);
    //             return -1;
    //         }
    //         kv = kv->next;
    //     }
    //     break;
    // }
    // case MSG_TYPE_PASS:
    // {
    //     msg_pass_t* pass = (msg_pass_t*)msg->value;
    //     pu_param_t* pu_param = (pu_param_t*)pu->hanlder.param;
    //     if(NULL == pu_param)
    //     {
    //         return -1;
    //     }
    //     int i = 0;
    //     pthread_mutex_lock(&pu->hanlder.lock);
    //     msleep(10);
    //     modbus_flush(pu_param->ctx);
    //     modbus_set_debug(pu_param->ctx, TRUE);
    //     modbus_send_raw_data(pu_param->ctx,pass->stream,pass->cnt);
    //     memset(pass->stream,0,sizeof(pass->stream));
    //     pass->cnt = 0;
    //     pass->cnt = modbus_read_raw_data(pu_param->ctx,pass->stream,sizeof(pass->stream));
    //     modbus_set_debug(pu_param->ctx, FALSE);
    //     pthread_mutex_unlock(&pu->hanlder.lock);

    //     // 未收到数据或者出错
    //     if(pass->cnt <= 0) return pass->cnt;
    // }
    // default:
    //     break;
    // }

    return 0;
}